#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif


#include <GL/glew.h>
#include "VirtualGlobe.h"
#include <wx/image.h>

namespace VIS
{
	CVirtualGlobe::Tile::Tile(const TileId& id, GLuint glName)
		:m_id(id), m_glName(glName)
	{
	}

	bool CVirtualGlobe::Tile::operator==(const Tile &other)
	{
		return m_id == other.id() && m_glName == other.glName();
	}


	CVirtualGlobe::CVirtualGlobe(void)
		: m_size(10000), m_initLoad(false), m_ViewPort(NULL)
	{
		m_ViewPort = new CViewPort;
		m_camera = new CSphereCamera;
	}


	CVirtualGlobe::~CVirtualGlobe(void)
	{
		delete m_ViewPort;
		delete m_camera;
	}

	void CVirtualGlobe::initGlobe()
	{
	}

	void CVirtualGlobe::renderTile(const Tile&_tile)
	{
		static const int NumLatitudes = 15;
		static const int NumLongitudes = 15;

		const int numXTiles = m_ViewPort->NumXTiles();
		const int numYTiles = m_ViewPort->NumYTiles();

		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);
		glEnable(GL_TEXTURE_2D);

		glBindTexture(GL_TEXTURE_2D, _tile.glName());

		for(int row = 0; row < NumLatitudes; row++)
		{
			glBegin(GL_TRIANGLE_STRIP);
			
			for(int col = 0; col <= NumLongitudes; col++)
			{
				const float x =  (_tile.id().x()*NumLongitudes + col  )* 1.0f / (NumLongitudes *numXTiles);
				const float y1 = (_tile.id().y()*NumLatitudes  +  row )* 1.0f / (NumLatitudes  *numYTiles);
				const float y2 = (_tile.id().y()*NumLatitudes  + row+1)* 1.0f / (NumLatitudes  *numYTiles);

				float lon, lat;
				float w0, w1, w2;

				geoCoord(x, y1, lon, lat);
				m_ViewPort->VertCoord(lon,lat, w0, w1, w2);
				glTexCoord2d(col*1.0/NumLatitudes, row*1.0/NumLongitudes);
				glVertex3d(w0,w1,w2);

				geoCoord(x, y2, lon, lat);
				m_ViewPort->VertCoord(lon, lat, w0, w1, w2);
				glTexCoord2d(col*1.0/NumLatitudes, (row+1)*1.0/NumLongitudes);
				glVertex3d(w0,w1,w2);
			}

			glEnd();
		}
	}

	void CVirtualGlobe::updateTiles()
	{
		int level = 1;
		int numYTiles = (int)pow(2.0, level);
		int numXTiles = 2*numYTiles;
		m_ViewPort->SetNumXTiles(numXTiles);
		m_ViewPort->SetNumYTiles(numYTiles);

		const int startXTile = 0;
		const int startYTile = 0;
		int endXTile = startXTile + numXTiles;
		int endYTile = startYTile + numYTiles;

		std::hash<string> str_hash;
		const int hash = str_hash("earth/bluemarble");
		
		for(int i = startXTile; i < endXTile; ++i)
		{
			for(int j = startYTile; j < endYTile; ++j)
			{
				const TileId id(hash, level, i%numXTiles, j%numYTiles);
				char image_name_c[255];
				sprintf_s(image_name_c, "%s%i/%06d/%06d_%06d.jpg", 
					"data/globe/", 
					level,
					id.y(),
					id.y(),
					id.x());

				wxImage image;
				GLuint g_texture;

				glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
				glGenTextures(1, &g_texture);
				glBindTexture(GL_TEXTURE_2D, g_texture);

				if(image.LoadFile(image_name_c))
				{
					int _width  = image.GetWidth();
					int _height = image.GetHeight();

					gluBuild2DMipmaps(GL_TEXTURE_2D,
						GL_RGB,
						_width,
						_height,
						GL_RGB,
						GL_UNSIGNED_BYTE,
						image.GetData()
						);

					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

				}
				else
					wxLogMessage("Failed! Cound Not Load Virtual Globe Textue Image!");

				m_tiles.push_back(Tile(id, g_texture));
			}//end of inner for loop
		}// end of first for loop
	}



	void CVirtualGlobe::drawGlobe()
	{
		glPushAttrib(GL_TEXTURE_BIT);

		glColor3f(1.0f, 1.0f, 1.0f);//delete it when using shader
		list<Tile>::iterator it = m_tiles.begin();
		for(; it != m_tiles.end(); it++)
			renderTile(*it);

		if(!m_initLoad)
		{
			initGlobe();
			m_initLoad = true;
			updateTiles();
		}

		glPopAttrib();
	}

}
